using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public delegate void PageChangedEventHandler(object sender, PageChangedEventArgs e);

#region PagingMode enum
public enum PagingMode
{
    Cached,
    NonCached
}
#endregion

#region PagerStyle enum
public enum PagerStyle
{
    NextPrev,
    NumericPages
}
#endregion
#region VirtualRecordCount class
public class VirtualRecordCount
{
    public int RecordCount;
    public int PageCount;
    public int RecordsInLastPage;
}
#endregion
public class PageChangedEventArgs : EventArgs
{
    public int OldPageIndex;
    public int NewPageIndex;
}
public partial class ProtonPager : System.Web.UI.UserControl
{
    private string ConnectionString = ConfigurationManager.ConnectionStrings[0].ToString();
    public event PageChangedEventHandler PageIndexChanged;

    public int CacheDuration
    {
        get { return Convert.ToInt32(ViewState["CacheDuration"]); }
        set { ViewState["CacheDuration"] = value; }
    }

    public PagingMode PagingMode
    {
        get { return (PagingMode)ViewState["PagingMode"]; }
        set { ViewState["PagingMode"] = value; }
    }


    public string ControlToPaginate
    {
        get { return Convert.ToString(ViewState["ControlToPaginate"]); }
        set { ViewState["ControlToPaginate"] = value; }
    }

    public int ItemsPerPage
    {
        get { return Convert.ToInt32(ViewState["ItemsPerPage"]); }
        set { ViewState["ItemsPerPage"] = value; }
    }

    public int CurrentPageIndex
    {
        get { return Convert.ToInt32(lbCurrentPage.Text) - 1; }
        set { lbCurrentPage.Text = Convert.ToString(value + 1); }
    }

    public string SelectCommand
    {
        get { return Convert.ToString(ViewState["SelectCommand"]); }
        set { ViewState["SelectCommand"] = value; }
    }
    public string RecordCount
    {
        get { return Convert.ToString(ViewState["RecordCount"]); }
        set { ViewState["RecordCount"] = value; }
    }

    public string SortField
    {
        get { return Convert.ToString(ViewState["SortKeyField"]); }
        set { ViewState["SortKeyField"] = value; }
    }

    public int PageCount
    {
        get { return TotalPages; }
    }

    protected int TotalPages
    {
        get { return Convert.ToInt32(ViewState["TotalPages"]); }
        set { ViewState["TotalPages"] = value; }
    }

    #region  PRIVATE DATA MEMBERS
    // ***********************************************************************
    // PRIVATE members
    private PagedDataSource _dataSource;
    private Control _controlToPaginate;
    private string CacheKeyName
    {
        get { return Page.Request.FilePath + "_" + UniqueID + "_Data"; }
    }
    private string CurrentPageText = "<b>Page</b> {0} <b>of</b> {1}";
    private string NoPageSelectedText = "No page selected.";
    private string QueryPageCommandText = "SELECT * FROM " +
        "(SELECT TOP {0} * FROM " +
        "(SELECT TOP {1} * FROM ({2}) AS t0 ORDER BY {3} {4}) AS t1 " +
        "ORDER BY {3} {5}) AS t2 " +
        "ORDER BY {3}";
    private string QueryCountCommandText = "SELECT COUNT(*) FROM ({0}) AS t0";
    // ***********************************************************************
    #endregion
    protected void Page_Load(object sender, EventArgs e)
    {

        if (!Page.IsPostBack)
        {
            this.CurrentPageIndex = 0;
            lbCurrentPage.Text = "1";
            GoToPage(0);
            lbTotalPage.Text = PageCount.ToString();
            lbRecordCount.Text = RecordCount;
            for (int i = 0; i < PageCount; i++)
            {
                ddlGoToPage.Items.Add(new ListItem(Convert.ToString(i + 1)));
            }
        }
        else
        {
            GoToPage(CurrentPageIndex);
            lbTotalPage.Text = PageCount.ToString();
            lbRecordCount.Text = RecordCount;
        }
        
    }
    protected void btnFirst_Click(object sender, ImageClickEventArgs e)
    {
        ddlGoToPage.SelectedIndex = 0;
        GoToPage(0);
    }
    protected void btnPrevious_Click(object sender, ImageClickEventArgs e)
    {
        if (CurrentPageIndex !=0)
        {
            ddlGoToPage.SelectedIndex = CurrentPageIndex - 1;
        }
        GoToPage(CurrentPageIndex - 1);
    }
    protected void btnNext_Click(object sender, ImageClickEventArgs e)
    {
        if (ddlGoToPage.Items.Count -1> CurrentPageIndex)
        {
            ddlGoToPage.SelectedIndex = CurrentPageIndex + 1;
        }
            GoToPage(CurrentPageIndex + 1);
       
    }
    protected void Last_Click(object sender, ImageClickEventArgs e)
    {
        ddlGoToPage.SelectedIndex = TotalPages - 1;
        GoToPage(TotalPages - 1);
    }
    public void myDataBind()
    {
        if (ControlToPaginate == "")
            return;
        _controlToPaginate = this.Parent.FindControl(ControlToPaginate);
        if (_controlToPaginate == null)
            return;
        if (!(_controlToPaginate is BaseDataList || _controlToPaginate is GridView || _controlToPaginate is ListControl || _controlToPaginate is Repeater))
            return;

        // Ensures enough info to connect and query is specified
        if (ConnectionString == "" || SelectCommand == "")
            return;

        // Fetch data
        if (PagingMode == PagingMode.Cached)
            FetchAllData();
        else
        {
            //if (SortField == "")
            //	return;
            FetchPageData();
        }

        // Bind data to the buddy control
        BaseDataList baseDataListControl = null;
        ListControl listControl = null;
        Repeater rp = null;
        GridView gv = null;
        if (_controlToPaginate is BaseDataList)
        {
            baseDataListControl = (BaseDataList)_controlToPaginate;
            baseDataListControl.DataSource = _dataSource;
            baseDataListControl.DataBind();
            return;
        }
        if (_controlToPaginate is ListControl)
        {
            listControl = (ListControl)_controlToPaginate;
            listControl.Items.Clear();
            listControl.DataSource = _dataSource;
            listControl.DataBind();
            return;
        }
        if (_controlToPaginate is Repeater)
        {
            rp = (Repeater)_controlToPaginate;
            rp.DataSource = _dataSource;
            rp.DataBind();
        }
        if (_controlToPaginate is GridView)
        {
            gv = (GridView)_controlToPaginate;
            gv.DataSource = _dataSource;
            gv.DataBind();
        }
    }
    private void ValidatePageIndex()
    {
        if (CurrentPageIndex <= 0)
            CurrentPageIndex = 0;

        if (CurrentPageIndex >= TotalPages)
            CurrentPageIndex = TotalPages - 1;

        return;
    }
    private void FetchAllData()
    {
        // Looks for data in the ASP.NET Cache
        DataTable data;
        data = (DataTable)Page.Cache[CacheKeyName];
        if (data == null)
        {
            // Fix SelectCommand with order-by info
            AdjustSelectCommand(true);

            // If data expired or has never been fetched, go to the database
            SqlDataAdapter adapter = new SqlDataAdapter(SelectCommand, ConnectionString);
            data = new DataTable();
            adapter.Fill(data);

            
            Page.Cache.Insert(CacheKeyName, data, null,
                DateTime.Now.AddSeconds(CacheDuration),
                System.Web.Caching.Cache.NoSlidingExpiration);
        }

        // Configures the paged data source component
        if (_dataSource == null)
            _dataSource = new PagedDataSource();
        _dataSource.DataSource = data.DefaultView; // must be IEnumerable!
        _dataSource.AllowPaging = true;
        _dataSource.PageSize = ItemsPerPage;
        TotalPages = _dataSource.PageCount;

        // Ensures the page index is valid 
        ValidatePageIndex();
        if (CurrentPageIndex == -1)
        {
            _dataSource = null;
            return;
        }

        // Selects the page to view
        _dataSource.CurrentPageIndex = CurrentPageIndex;
    }
    private void FetchPageData()
    {
        // Need a validated page index to fetch data.
        // Also need the virtual page count to validate the page index
        AdjustSelectCommand(false);
        VirtualRecordCount countInfo = CalculateVirtualRecordCount();
        TotalPages = countInfo.PageCount;
        RecordCount = countInfo.RecordCount.ToString();
        // Validate the page number (ensures CurrentPageIndex is valid or -1)
        ValidatePageIndex();
        if (CurrentPageIndex == -1)
            return;

        // Prepare and run the command
        SqlCommand cmd = PrepareCommand(countInfo);
        if (cmd == null)
            return;
        SqlDataAdapter adapter = new SqlDataAdapter(cmd);
        DataTable data = new DataTable();
        adapter.Fill(data);

        // Configures the paged data source component
        if (_dataSource == null)
            _dataSource = new PagedDataSource();
        //_dataSource.AllowCustomPaging = true;
        //_dataSource.AllowPaging = true;
        //_dataSource.CurrentPageIndex = 0;
        //_dataSource.PageSize = ItemsPerPage;
        //_dataSource.VirtualCount = countInfo.RecordCount;
        _dataSource.DataSource = data.DefaultView;
    }
    private void AdjustSelectCommand(bool addCustomSortInfo)
    {
        // Truncate where ORDER BY is found
        string temp = SelectCommand.ToLower();
        int pos = temp.IndexOf("order by");
        if (pos > -1)
            SelectCommand = SelectCommand.Substring(0, pos);

        // Add new ORDER BY info if SortKeyField is specified
        if (SortField != "" && addCustomSortInfo)
            SelectCommand += " ORDER BY " + SortField;
    }
    private VirtualRecordCount CalculateVirtualRecordCount()
    {
        VirtualRecordCount count = new VirtualRecordCount();

        // Calculate the virtual number of records from the query
        
        count.RecordCount = GetQueryVirtualCount();
        count.RecordsInLastPage = ItemsPerPage;

        // Calculate the correspondent number of pages
        int lastPage = count.RecordCount / ItemsPerPage;
        int remainder = count.RecordCount % ItemsPerPage;
        if (remainder > 0)
            lastPage++;
        count.PageCount = lastPage;

        // Calculate the number of items in the last page
        if (remainder > 0)
            count.RecordsInLastPage = remainder;
        return count;
    }
    private SqlCommand PrepareCommand(VirtualRecordCount countInfo)
    {
        // No sort field specified: figure it out
        if (SortField == "")
        {
            // Get metadata for all columns and choose either the primary key
            // or the 
            string text = "SET FMTONLY ON;" + SelectCommand + ";SET FMTONLY OFF;";
            SqlDataAdapter adapter = new SqlDataAdapter(text, ConnectionString);
            DataTable t = new DataTable();
            adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
            adapter.Fill(t);
            DataColumn col = null;
            if (t.PrimaryKey.Length > 0)
                col = t.PrimaryKey[0];
            else
                col = t.Columns[0];
            SortField = col.ColumnName;
        }

        // Determines how many records are to be retrieved.
        // The last page could require less than other pages
        int recsToRetrieve = ItemsPerPage;
        if (CurrentPageIndex == countInfo.PageCount - 1)
            //recsToRetrieve = countInfo.RecordsInLastPage;
            recsToRetrieve = 1;

        string cmdText = String.Format(QueryPageCommandText,
            recsToRetrieve,						// {0} --> page size
            ItemsPerPage * (CurrentPageIndex + 1),	// {1} --> size * index
            SelectCommand,						// {2} --> base query
            SortField,							// {3} --> key field in the query
            "ASC",								// Default to ascending order
            "DESC");

        //Response.Write("<h3>" + cmdText + "</h3>");

        SqlConnection conn = new SqlConnection(ConnectionString);
        SqlCommand cmd = new SqlCommand(cmdText, conn);
        return cmd;
    }
    private int GetQueryVirtualCount()
    {
        string cmdText = String.Format(QueryCountCommandText, SelectCommand);
        SqlConnection conn = new SqlConnection(ConnectionString);
        SqlCommand cmd = new SqlCommand(cmdText, conn);

        cmd.Connection.Open();
        int recCount = (int)cmd.ExecuteScalar();
        cmd.Connection.Close();

        return recCount;
    }
    private void GoToPage(int pageIndex)
    {
        // Prepares event data
        PageChangedEventArgs e = new PageChangedEventArgs();
        e.OldPageIndex = CurrentPageIndex;
        e.NewPageIndex = pageIndex;

        // Updates the current index
        CurrentPageIndex = pageIndex;

        // Fires the page changed event
        //OnPageIndexChanged(e);

        // Binds new data
        myDataBind();
    }
    public void ClearCache()
    {
        if (PagingMode == PagingMode.Cached)
            Page.Cache.Remove(CacheKeyName);
    }
    protected void btnGoPage_Click(object sender, EventArgs e)
    {
        GoToPage(Convert.ToInt32(ddlGoToPage.SelectedValue) - 1);
    }

    public void Reload()
    {
        GoToPage(Convert.ToInt32(CurrentPageIndex));
    }
}
